﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SoftwareMonkeys.LogClimber.Entities;
using SoftwareMonkeys.LogClimber.Controls;
using SoftwareMonkeys.LogClimber.Business;
using System.Reflection;
using System.IO;

namespace SoftwareMonkeys.LogClimber
{
    public partial class Display : Form
    {
    	public string[] SelectedComponents
    	{
    		get {
    			return new ComponentListBuilder(componentList).GetSelectedComponents();
    		}
    	}
    	
        public string DefaultTitle = "SoftwareMonkeys Log Viewer";

        public LogProject Project;
        public string LogFilePath = String.Empty;

        public Display()
        {
            InitializeComponent();
        }

        private void Display_Load(object sender, EventArgs e)
        {
            Text = DefaultTitle;

            RefreshRecent();
        }

        private void projectNewMenuItem_Click(object sender, EventArgs e)
        {
            NewProjectDialog dialog = new NewProjectDialog();
            DialogResult result = dialog.ShowDialog();

            if (dialog.Project != null)
            {
                LoadProject(dialog.Project);
            }
        }

        private void projectOpenMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult result = openProjectDialog.ShowDialog(this);
            if (result != DialogResult.Cancel &&
                result != DialogResult.Abort)
            {
                string projectFilePath = openProjectDialog.FileName;

                LogProjectLoader loader = new LogProjectLoader();

                Project = loader.Load(projectFilePath);

                LoadProject(Project);

                status.Text = "Loaded project: " + Project.Name;
            }
        }

        private void AddToRecent(LogProject project)
        {
            string recentProjectsDirectory = GetRecentProjectsDirectory();

            if (!Directory.Exists(recentProjectsDirectory))
                Directory.CreateDirectory(recentProjectsDirectory);

            string recentProjectPath = recentProjectsDirectory + Path.DirectorySeparatorChar
                + project.Name + ".logproject";

            XmlSaver saver = new XmlSaver();
            saver.Save(project, recentProjectPath);

            RefreshRecent();
        }

        private string GetRecentProjectsDirectory()
        {
            string dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
                + Path.DirectorySeparatorChar + "Recent";

            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);

            return dir;
        }

        private void RefreshRecent()
        {
            projectRecentMenuItem.DropDownItems.Clear();

            projectRecentMenuItem.Enabled = true;

            foreach (string file in Directory.GetFiles(GetRecentProjectsDirectory()))
            {
                LogProjectLoader loader = new LogProjectLoader();
                LogProject project = loader.Load(file);
                projectRecentMenuItem.DropDownItems.Add(project.Name, null, new EventHandler(ProjectRecent_Click));
            }
        }

        private void ProjectRecent_Click(object sender, EventArgs e)
        {
            string name = ((ToolStripMenuItem)sender).Text;
            LoadRecent(name);
        }

        private void LoadRecent(string name)
        {
            LogProjectFileNamer namer = new LogProjectFileNamer();
            string path = namer.CreateLogProjectFilePath(GetRecentProjectsDirectory(),
                name);

            LogProjectLoader loader = new LogProjectLoader();

            LogProject project = loader.Load(path);

            LoadProject(project);
        }

        private void LoadProject(LogProject project)
        {
            Project = project;
            status.Text = "Loaded project: " + project.Name;

            this.Text = project.Name + " Logs - " + project.WwwDirectory;

            // Clear the LogFilePath property because it's an entire project that has been loaded and not just a single log
            LogFilePath = String.Empty;
            
            AddToRecent(Project);

            LoadLogs();
        }

        private void LoadLogs()
        {
            LogTreeLoader loader = new LogTreeLoader();

            Log[] logs = new Log[] { };
            
			try
			{
            // If a current project is open then load its logs
            if (Project != null)
                logs = loader.LoadLogs(Project.WwwDirectory);
            // else
            // Just load empty logs which will clear the tree
			}
			catch (Exception ex)
			{
				MessageBox.Show(@"An error occurred when trying to load the logs. This may mean that they are corrupt.
					Exception output:
					" + ex.ToString());
			}
			
			RefreshLogs(logs, true);
        }


        private void logTree_KeyUp(object sender, KeyEventArgs e)
        {


            if (e.KeyData == Keys.F5)
            {
                if (Project != null)
                {
                    LoadProject(Project);
                }
                e.Handled = true;
            }
        }

        private void ShowStackTrace(Entry entry)
        {
            stackTraceBox.Lines = GetStackTrace(entry).Split('\n');
        }

        private void entryMenu_Opening(object sender, CancelEventArgs e)
        {

            Point pointToClient = this.logTree.PointToClient(Cursor.Position);
            TreeNode node = this.logTree.GetNodeAt(pointToClient);
            if (node != null)
            {

            }

        }

        Entry SelectedEntry = null;

        private void logTree_MouseUp(object sender, MouseEventArgs e)
        {
            if(e.Button == MouseButtons.Right)
            {

                // Select the clicked node
                logTree.SelectedNode = logTree.GetNodeAt(e.X, e.Y);

                if(logTree.SelectedNode != null)
                {
                    SelectedEntry = (Entry)logTree.SelectedNode.Tag;

                    entryMenu.Show(logTree, e.Location);
                }
            }

        }
        
        private string GetStackTrace(Entry entry)
        {
            if (entry != null)
            {
            	if (Project != null)
                	return new StackTraceLoader().Load(Project, entry);
            	else
            		return new StackTraceLoader().Load(Path.GetDirectoryName(LogFilePath), entry);
            }
            else
                return String.Empty;
        }

        private void logTree_MouseDown(object sender, MouseEventArgs e)
        {

            TreeNode selNode = (TreeNode)logTree.GetNodeAt(logTree.PointToClient(Cursor.Position));

            if (selNode != null)
            {
                if (selNode.Tag != null)
                {
                    SelectedEntry = (Entry)selNode.Tag;
                }
            }

            if (SelectedEntry != null)
                ShowStackTrace(SelectedEntry);
        }

        private void exitMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void projectCloseMenuItem_Click(object sender, EventArgs e)
        {
            CloseProject();
        }

        private void CloseProject()
        {
            Project = null;

            LoadLogs();

            Text = DefaultTitle;
        }


        
        void OpenLogMenuItemClick(object sender, EventArgs e)
        {
        	DialogResult result = openLogDialog.ShowDialog(this);
            if (result != DialogResult.Cancel &&
                result != DialogResult.Abort)
            {
                string logFilePath = openLogDialog.FileName;

                //LogProjectLoader loader = new LogProjectLoader();

                //Project = loader.Load(projectFilePath);

                LoadLog(logFilePath);

                status.Text = "Log loaded successfully.";
            }
        }
        
        private void LoadLog(string logFilePath)
        {
        	
            LogTreeLoader loader = new LogTreeLoader();

            Log log = null;
            
			try
			{
                log = loader.LoadLog(logFilePath);
                
                LogFilePath = logFilePath;
			}
			catch (Exception ex)
			{
				MessageBox.Show(@"An error occurred when trying to load the logs. This may mean that they are corrupt.
					Exception output:
					" + ex.ToString());
			}
			
			RefreshLog(log, true);
        }
        
        void HideToolStripMenuItemClick(object sender, EventArgs e)
        {
        	//string componentName =
        }
        
        void ComponentListSelectedValueChanged(object sender, EventArgs e)
        {
        	RefreshLogs();
        }
        
        public Log[] CurrentLogs = new Log[] {};
        
        public void RefreshLogs()
        {
        	RefreshLogs(CurrentLogs);
        }
        
        public void RefreshLogs(Log[] logs)
        {
        	RefreshLogs(logs, false);
        }
        
        public void RefreshLogs(Log[] logs, bool refreshComponentList)
        {
        	CurrentLogs = logs;
        	if (refreshComponentList)
				new ComponentListBuilder(componentList).Show(logs);
            new LogTreeViewBuilder(logTree, SelectedComponents).Show(logs);
        }
        
        public void RefreshLog(Log log)
        {
        	RefreshLog(log, false);
        }
        public void RefreshLog(Log log, bool refreshComponentsList)
        {
        	
        	CurrentLogs = new Log[] {log};
        	
        	if (refreshComponentsList)
				new ComponentListBuilder(componentList).Show(log);
				
            new LogTreeViewBuilder(logTree, SelectedComponents).Show(log);
        }
        
    }
}
